package com.changgou.seckill.task;

import com.alibaba.fastjson.JSON;
import com.changgou.seckill.dao.SeckillGoodsMapper;
import com.changgou.seckill.dao.SeckillOrderMapper;
import com.changgou.seckill.mq.queue.QueueConfig;
import com.changgou.seckill.pojo.SeckillGoods;
import com.changgou.seckill.pojo.SeckillOrder;
import entity.IdWorker;
import entity.SeckillStatus;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class MultiThreadingCreateOrder {

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /***
     * @Async:该方法会异步执行，底层是多线程方式
     */
    @Async
    public void createOrder(){
        try {
            //从redis队列中获取订单信息
            SeckillStatus seckillStatus = (SeckillStatus) redisTemplate.boundListOps("SeckillOrderQueue").rightPop();
            String username = seckillStatus.getUsername();
            String time = seckillStatus.getTime();
            Long id = seckillStatus.getGoodsId();
            //同步从redis中获取商品数量队列信息，防止超卖现象
            Object rightPop = redisTemplate.boundListOps("SeckillGoodsCountList_" + id).rightPop();
            if (rightPop==null){
                //清除用户当前排队信息
                clearQueue(seckillStatus);
                return;
            }

            //获取商品数据
            SeckillGoods goods = (SeckillGoods) redisTemplate.boundHashOps("Seckill_" + time).get(id);
            //如果没有库存，则直接抛出异常
            if(goods==null || goods.getStockCount()<=0){
                throw new RuntimeException("已售罄!");
            }
            //如果有库存，则创建秒杀商品订单
            SeckillOrder seckillOrder = new SeckillOrder();
            seckillOrder.setId(idWorker.nextId());
            seckillOrder.setSeckillId(id);
            seckillOrder.setMoney(goods.getCostPrice());
            seckillOrder.setUserId(username);
            seckillOrder.setCreateTime(new Date());
            seckillOrder.setStatus("0");

            //将秒杀订单存入到Redis中
            redisTemplate.boundHashOps("SeckillOrder").put(username,seckillOrder);
            //同步更新查询用户订单详情redis
            seckillStatus.setOrderId(seckillOrder.getId());
            seckillStatus.setMoney(Float.valueOf(seckillOrder.getMoney()));
            //秒杀状态  1:排队中，2:秒杀等待支付,3:支付超时，4:秒杀失败,5:支付完成
            seckillStatus.setStatus(2);
            redisTemplate.boundHashOps("UserSeckillQuery").put(username,seckillStatus);

            //库存减少
            goods.setStockCount(goods.getStockCount()-1);
/*
            //判断当前商品是否还有库存
            //判断当前商品redis队列中是否还有商品
            Long size = redisTemplate.boundListOps("SeckillGoodsCountList_" + id).size();*/

            //商品库存减一
            Long seckillGoodsCount = redisTemplate.boundHashOps("SeckillGoodsCount").increment(id, -1);
            if(seckillGoodsCount<=0){
                //同步商品数量
                goods.setStockCount(seckillGoodsCount.intValue());
                //并且将商品数据同步到MySQL中
                seckillGoodsMapper.updateByPrimaryKeySelective(goods);
                //如果没有库存,则清空Redis缓存中该商品
                redisTemplate.boundHashOps("Seckill_" + time).delete(id);
                //清除自增计数器
                redisTemplate.boundHashOps("SeckillGoodsCount").delete(id);
            }else{
                //如果有库存，则将数据重置到Reids中
                redisTemplate.boundHashOps("Seckill_" + time).put(id,goods);
            }
            System.out.println("抢单完成");
            //添加抢单订单
            seckillOrderMapper.insertSelective(seckillOrder);
            //给延迟队列发消息
            //将订单id发送到死信队列
            String format = new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date());
            System.out.println("发送时间："+format);
            seckillStatus.setOrderId(seckillOrder.getId());
            String jsonString = JSON.toJSONString(seckillStatus);
            rabbitTemplate.convertAndSend(QueueConfig.QUEUE_MESSAGE_DELAY, (Object) jsonString, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    message.getMessageProperties().setExpiration("10000");  //半小时后发送信息，检测订单支付状态
                    return message;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /***
     * 清理用户排队信息
     * @param seckillStatus
     */
    public void clearQueue(SeckillStatus seckillStatus){
        //清理排队标示
        redisTemplate.boundHashOps("userQueueCount").delete(seckillStatus.getUsername());

        //清理抢单标示
        redisTemplate.boundHashOps("UserSeckillQuery").delete(seckillStatus.getUsername());
    }

    /**
     * 异步执行测试
     */
    @Async
    public void createOrderTest(){
        try {
            System.out.println("准备执行....");
            Thread.sleep(20000);
            System.out.println("开始执行....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


